/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GraphPackage;

import GUIUtilities.ColorUtilities;
import GUIUtilities.LabelManager;
import GUIUtilities.StringUtilities;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Polygon;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 *
 * @author Heather
 */
public class VerticalBarGraph extends BarGraph
{

  private BarGraphBars barsPanel;
  private Image buffer;
  private Graphics bufferG;
  //private int numberOfYAxisValuesExcludingZero = 10;
  // this represents how high we place the x axis
  private double xAxisPercentage = 0;

  public VerticalBarGraph()
  {
    this.setBackground(bgColor);
    barsPanel = new BarGraphBars();

    this.setLayout(null);
    add(barsPanel);
    barsPanel.setLayout(null);
    barsPanel.setSize(getSize());
    barsPanel.setLocation(0, 0);
    setDefaultLabelTexts();
    setupLabelLocations();
    resizeAllLabels();
    setupComponentOrder();
  }

  public VerticalBarGraph(int numberOfBars)//, int width, int height)
  {
    this.setBackground(bgColor);
    barsPanel = new BarGraphBars();

    for (int i = 0; i < numberOfBars; i++)
    {
      barValues.add(50.0);
      System.out.println("this is the maxcolor: " + MAX_COLOR_CONSTRAINT);
      Color c = ColorUtilities.getRandomColorWithConstraints(MIN_COLOR_CONSTRAINT, 230);//MAX_COLOR_CONSTRAINT);
      currentBarColors.add(c);
      defaultBarColors.add(c);
    //barLabels.add(new JLabel());
    //xAxisLabels.add(new JLabel());
    }

    this.setLayout(null);
    add(barsPanel);
    barsPanel.setLayout(null);
    barsPanel.setSize(getSize());
    System.out.println("this is the size of this panel: " + getSize());
    System.out.println("bars panel size: " + barsPanel.getSize());
    barsPanel.setLocation(0, 0);
    setDefaultLabelTexts();
    setupLabelLocations();
    resizeAllLabels();
    setupComponentOrder();
  }

  public VerticalBarGraph(int numberOfBars, double maxValue, double minValue, double increment)//, int width, int height)
  {
    this.maxValue = maxValue;
    this.minValue = minValue;
    this.yAxisLabelsIncrement = increment;
    this.setBackground(bgColor);
    barsPanel = new BarGraphBars();

    for (int i = 0; i < numberOfBars; i++)
    {
      barValues.add(50.0);
      System.out.println("max color constraint line constructor: " + MAX_COLOR_CONSTRAINT);
      Color c = ColorUtilities.getRandomColorWithConstraints(MIN_COLOR_CONSTRAINT, 230);//MAX_COLOR_CONSTRAINT);
      currentBarColors.add(c);
      defaultBarColors.add(c);
    //barLabels.add(new JLabel());
    //xAxisLabels.add(new JLabel());
    }

    this.setLayout(null);
    add(barsPanel);
    barsPanel.setLayout(null);
    barsPanel.setSize(getSize());
    System.out.println("this is the size of this panel: " + getSize());
    System.out.println("bars panel size: " + barsPanel.getSize());
    barsPanel.setLocation(0, 0);
    setDefaultLabelTexts();
    setupLabelLocations();
    resizeAllLabels();
    setupComponentOrder();
  }

  protected void calculateVariables()
  {
    super.calculateVariables();
    maxDimension = graphHeight * (Math.abs(maxValue) / (Math.abs(minValue) + Math.abs(maxValue)));
    minDimension = graphHeight * (Math.abs(minValue) / (Math.abs(minValue) + Math.abs(maxValue)));
    xAxisPercentage = Math.abs(maxValue) / (Math.abs(minValue) + Math.abs(maxValue));
  }

  // makes sure all the components are overlapping properly
  private void setupComponentOrder()
  {
    removeAll();

    for (int i = 0; i < getBarLabels().size(); i++)
    {
      add(getBarLabels().get(i));
    //System.out.println("size of label: " + barLabels.get(i).getSize());
    }

    for (int i = 0; i < xAxisLabels.size(); i++)
    {
      add(xAxisLabels.get(i));
    }

    for (int i = 0; i < yAxisLabels.size(); i++)
    {
      add(yAxisLabels.get(i));
    }

    add(graphTitleLabel);
    add(barsPanel);
  }

  // sets the locations of the labels
  /*
   *     private Vector<JLabel> barLabels = new Vector<JLabel>();
  private Vector<JLabel> xAxisLabels = new Vector<JLabel>();
  private Vector<JLabel> yAxisLabels = new Vector<JLabel>();
   */
  private void setupLabelLocations()
  {
    // these represent the locations of the labels.
    int x = 0;
    int y = 0;

    // placing the top title label
    x = (getSize().width / 2) - (graphTitleLabel.getSize().width / 2);
    y = (int) topLabelBorder / 2;
    graphTitleLabel.setLocation(x, y);
    Dimension titleD = LabelManager.getLabelDimensions(graphTitleLabel);
    graphTitleLabel.setSize(titleD);
    graphTitleLabel.setPreferredSize(titleD);
    //System.out.println("this si the size of the graph title: " + graphTitleLabel.getSize());

    // place the yAxisLabels
    calculateVariables();

    int labelHeightIncrement = 0;
    int xAxisY = (int) ((graphHeight * xAxisPercentage) + topLabelBorder);
    for (int i = 0; i < yAxisLabels.size(); i++)
    {
      JLabel currentYLabel = yAxisLabels.get(i);
      Dimension d = LabelManager.getLabelDimensions(currentYLabel);
      double value = Double.parseDouble(currentYLabel.getText());
      x = (int) leftLabelBorder - d.width;
      if (value > 0)
      {
        labelHeightIncrement = (int) ((yAxisLabelsIncrement / maxValue) * (graphHeight * (maxValue / (maxValue + Math.abs(minValue)))));
        y = xAxisY - (int) (labelHeightIncrement * (value / yAxisLabelsIncrement)) - d.height / 2;
      }
      else if (value < 0)
      {
        labelHeightIncrement = (int) ((yAxisLabelsIncrement / minValue) * (graphHeight * (maxValue / (maxValue + Math.abs(minValue)))));
        y = xAxisY + (int) (labelHeightIncrement * (value / yAxisLabelsIncrement)) - d.height / 2;
      }
      else
      {
        y = xAxisY - d.height / 2;
      }
      currentYLabel.setLocation(x, y);
    }

  // place the xAxisLabels

  }

  // resizes all the labels
  public void resizeAllLabels()
  {
    for (int i = 0; i < getBarLabels().size(); i++)
    {
      LabelManager.resizeLabel(getBarLabels().get(i));
    }

    for (int i = 0; i < xAxisLabels.size(); i++)
    {
      LabelManager.resizeLabel(xAxisLabels.get(i));
    }

    for (int i = 0; i < yAxisLabels.size(); i++)
    {
      LabelManager.resizeLabel(yAxisLabels.get(i));
    }

    LabelManager.resizeLabel(graphTitleLabel);
  }

  public void setNumberOfBars(int numberOfBars)
  {
    getBarValues().clear();
    getCurrentBarColors().clear();
    getBarLabels().clear();
    xAxisLabels.clear();

    for (int i = 0; i < numberOfBars; i++)
    {
      getBarValues().add(0.0);
      System.out.println("max color constraint set number of bars: " + MAX_COLOR_CONSTRAINT);
      Color c = ColorUtilities.getRandomColorWithConstraints(MIN_COLOR_CONSTRAINT, 230);//MAX_COLOR_CONSTRAINT);
      getCurrentBarColors().add(c);
      getDefaultBarColors().add(c);
      getBarLabels().add(new JLabel());
      xAxisLabels.add(new JLabel());
    }

    barsPanel.setSize(getSize());
    barsPanel.setLayout(null);
    barsPanel.setLocation(0, 0);
    setupComponentOrder();
  }

  public void setName(String name)
  {
    this.name = name;
  }

  public void setValue(int index, double newValue)
  {
    getBarValues().set(index, newValue);
  }

  public double getMaxBarValue()
  {
    return maxValue;
  }

  public void setMaxBarValue(double newMaxBarValue)
  {
    maxValue = newMaxBarValue;
  }

  public void setRandomBarValues()
  {
    for (int i = 0; i < getBarValues().size(); i++)
    {
      //barValues.set(i, minValue);
      if (randGen.nextDouble() > 0.5)
      {
        getBarValues().set(i, randGen.nextDouble() * maxValue);
      }
      else
      {
        getBarValues().set(i, randGen.nextDouble() * minValue);
      }
    //barValues.set(i, 10.0);
    }
  }

  public void setRandomBarColors()
  {
    for (int i = 0; i < getBarValues().size(); i++)
    {
      getCurrentBarColors().set(i, new Color(randGen.nextInt(255), randGen.nextInt(255), randGen.nextInt(255)));
    }
  }

  public void setDefaultLabelTexts()
  {
    //int numberOfBars = getBarValues().size();

    for (int i = 0; i < barLabels.size(); i++)
    {
      getBarLabels().get(i).setText("" + getBarValues().get(i));
    }

    for (JLabel xAxisLabel : xAxisLabels)
    {
      xAxisLabel.setText("bar");
    }

    createYAxisLabels();
    graphTitleLabel.setText("Graph Title");

    setupLabelLocations();
    setupComponentOrder();
  }

  private void createYAxisLabels()
  {
    yAxisLabels.clear();
    // first calculate how many labels will be able to fit based
    // on the maximum bar height
    calculateVariables();

    // first place the 0 value label
    JLabel zeroLabel = new JLabel("" + 0);
    Dimension zd = LabelManager.getLabelDimensions(zeroLabel);
    zeroLabel.setSize(zd);
    zeroLabel.setPreferredSize(zd);
    yAxisLabels.add(zeroLabel);
    add(zeroLabel);


    int numberOfPositiveLabels = (int) (maxValue / yAxisLabelsIncrement);
    for (int i = 1; i <= numberOfPositiveLabels; i++)
    {
      double value = i * yAxisLabelsIncrement;
      String valueString = StringUtilities.getTruncatedDecimalString(value, 2);
      JLabel newYLabel = new JLabel("" + valueString);
      Dimension d = LabelManager.getLabelDimensions(newYLabel);
      newYLabel.setSize(d);
      newYLabel.setPreferredSize(d);
      yAxisLabels.add(newYLabel);
      add(newYLabel);
    }

    int numberOfNegativeLabels = (int) (minValue / yAxisLabelsIncrement);
    for (int i = 1; i <= numberOfPositiveLabels; i++)
    {
      double value = -i * yAxisLabelsIncrement;
      String valueString = StringUtilities.getTruncatedDecimalString(value, 2);
      JLabel newYLabel = new JLabel("" + valueString);
      Dimension d = LabelManager.getLabelDimensions(newYLabel);
      newYLabel.setSize(d);
      newYLabel.setPreferredSize(d);
      yAxisLabels.add(newYLabel);
      add(newYLabel);
    }
  }

  public void setSize(Dimension d)
  {
    super.setSize(d);
    calculateVariables();
    buffer = null;
    barsPanel.setSize(d);
    setupLabelLocations();
    repaint();
  }

  public void setSize(int x, int y)
  {
    super.setSize(x, y);
    calculateVariables();
    buffer = null;
    barsPanel.setSize(x, y);
    setupLabelLocations();
    repaint();
  }

  public void setPreferredSize(Dimension d)
  {
    super.setPreferredSize(d);
    buffer = null;
    barsPanel.setPreferredSize(d);
    repaint();
  }

  /**
   * This is the rectangle stuff that needs to be drawn for bar graphs
   * @author Heather
   */
  private class BarGraphBars extends JPanel
  {

    public BarGraphBars()
    {
      super();
    }

    public void drawGraph(Graphics g)
    {
      // clear the window and setup the graphics objects
      g.setColor(bgColor);
      //bufferG.setColor(Color.red);
      g.fillRect(0, 0, getSize().width, getSize().height);

      // fill in the graph bg
      Color graphBGColor = Color.white;
      g.setColor(graphBGColor);
      g.fillRect((int) leftLabelBorder, (int) topLabelBorder, (int) graphWidth, (int) graphHeight);

      // start filling the lines in
      getBarPolygons().clear();
      double barWidth = (graphWidth - getTotalBarSpacing()) / getBarValues().size();
      double barSpace = getTotalBarSpacing() / (getBarValues().size() + 1);
      for (int i = 0; i < getBarValues().size(); i++)
      {
        // setting the proper color
        g.setColor(getCurrentBarColors().get(i));

        // calculate the coordinates
        double x = i * (barWidth + barSpace) + leftLabelBorder + barSpace;
        double y = 0;
        double barValue = getBarValues().get(i);
        double barHeight = 0;
        if (barValue >= 0)
        {
          barHeight = (barValue / maxValue) * maxDimension;
          y = topLabelBorder + (graphHeight - barHeight - minDimension);
        }
        else
        {
          barHeight = Math.abs(barValue / minValue) * minDimension;
          // if bar value is neg, we can just start it at the same y as the x axis
          y = (int) ((graphHeight * xAxisPercentage) + topLabelBorder);
        }

        Polygon barP = new Polygon();
        barP.addPoint((int) x, (int) y);
        barP.addPoint((int) x + (int) barWidth, (int) y);
        barP.addPoint((int) x + (int) barWidth, (int) y + (int) barHeight);
        barP.addPoint((int) x, (int) y + (int) barHeight);
        getBarPolygons().add(barP);

        g.fillPolygon(barP);
      }

      // draw the xAxis
      int xAxisH = 2;
      g.setColor(Color.black);
      // calculate where the x axis should be
      int xAxisX = (int) leftLabelBorder;
      int xAxisY = (int) ((graphHeight * xAxisPercentage) + topLabelBorder);
      g.fillRect(xAxisX, xAxisY, (int) (getSize().width - leftLabelBorder - rightBorder), xAxisH);

      // draw the yAxis
      int yAxisW = 2;
      g.setColor(Color.black);
      g.fillRect((int) leftLabelBorder, (int) topLabelBorder, (int) yAxisW, (int) graphHeight);
    }

    public void paint(Graphics g)
    {
      // This creates the buffer
      if (buffer == null)
      {
        int xBound = getSize().width;
        int yBound = getSize().height;

        buffer = this.createImage(xBound, yBound);
        bufferG = buffer.getGraphics();
        bufferG.setColor(Color.white);
        bufferG.fillRect(0, 0, xBound, yBound);
      }
      g.drawImage(buffer, 0, 0, this);
      drawGraph(g);
    }
  }
}
